# -*- coding:utf-8 -*-

import json
import os
import re
import sys
from copy import deepcopy
from itertools import combinations, repeat, takewhile
from json import encoder
from math import sqrt
from operator import add
from random import choice, uniform

import numpy as np
import igraph as ig

import bgl
import blf
import bpy
from bpy_extras import view3d_utils


encoder.FLOAT_REPR = lambda o: format(o, '.3f')

# privilege名称对应的功能说明
privileges = {
    "SeAssignPrimaryTokenPrivilege": "Replace a process-level token",
    "SeAuditPrivilege": "Generate security audits",
    "SeBackupPrivilege": "Backup files and directories",
    "SeChangeNotifyPrivilege": "Receive notifications of changes to files or directories",
    "SeCreateGlobalPrivilege": "Create global objects",
    "SeCreatePagefilePrivilege": "Create a pagefile",
    "SeCreatePermanentPrivilege": "Create permanent shared objects",
    "SeCreateTokenPrivilege": "Create a token object",
    "SeDebugPrivilege": "Debug programs",
    "SeImpersonatePrivilege": "Impersonate a client after authentication",
    "SeIncreaseBasePriorityPrivilege": "Increase scheduling priority",
    "SeIncreaseQuotaPrivilege": "Increase quotas",
    "SeLoadDriverPrivilege": "Load and unload device drivers",
    "SeLockMemoryPrivilege": "Lock pages in memory",
    "SeManageVolumePrivilege": "Manage the files on a volume",
    "SeProfileSingleProcessPrivilege": "Profile a single process",
    "SeRemoteShutdownPrivilege": "Force shutdown from a remote system",
    "SeRestorePrivilege": "Restore files and directories",
    "SeSecurityPrivilege": "Manage auditing and security log",
    "SeShutdownPrivilege": "Shut down the system",
    "SeSystemEnvironmentPrivilege": "Edit firmware environment values",
    "SeSystemProfilePrivilege": "Profile system performance",
    "SeSystemtimePrivilege": "Change the system time",
    "SeTakeOwnershipPrivilege": "Take ownership of files/objects",
    "SeTcbPrivilege": "Act as part of the operating system",
    "SeUndockPrivilege": "Remove computer from docking station"
}

# blender add-on部分——tool shelf中的Drawing Line部分
bl_info = {
    "name": "Simple Line Drawing",
    "author": "lwm",
    "location": "View3D > Tools > Drawing",
    "version": (1, 0, 0),
    "blender": (2, 7, 9),
    "description": "Minimal add-on for line drawing"
}

#color and font
rgb_label = (1, 0.8, 0.1, 1.0)
font_size = 16
font_id = 0

def gl_pts(context, v):
    return view3d_utils.location_3d_to_region_2d(context.region, context.space_data.region_3d, v)

def draw_name(context, ob, rgb_label, fsize):
    a = gl_pts(context, ob.location)
    bgl.glColor4f(rgb_label[0], rgb_label[1], rgb_label[2], rgb_label[3])
    draw_text(a, ob.name, fsize)

def draw_text(v, display_text, fsize, font_id=0):
    if v:
        blf.size(font_id, font_size, 72)
        blf.position(font_id, v[0], v[1], 0)
        blf.draw(font_id, display_text)
    return

def draw_line(v1, v2):
    if v1 and v2:
        bgl.glBegin(bgl.GL_LINES)
        bgl.glVertex2f(*v1)
        bgl.glVertex2f(*v2)
        bgl.glEnd()

def draw_main(context):
    scene = context.scene

    rgb_line = (0.173, 0.545, 1.0, 1.0)
    rgb_label = (0.1, 0.1, 0.1, 1.0)
    fsize = 16

    bgl.glEnable(bgl.GL_BLEND)
    bgl.glLineWidth(1)
    bgl.glColor4f(*rgb_line)

    for edge in network["edges"]:
        # 通过遍历获取源和目标的位置
        source_name = edge["source"]
        target_name = edge["target"]
        source_obj = bpy.data.objects[source_name]
        target_obj = bpy.data.objects[target_name]
        # source_obj = target_obj.parent

        # 如果两个端点没有隐藏
        if (not source_obj.hide) and (not target_obj.hide):
            v1 = gl_pts(context, source_obj.matrix_world.to_translation())
            v2 = gl_pts(context, target_obj.matrix_world.to_translation())
            draw_line(v1, v2)

    # Store reference to active object
    ob = context.object
    if scene.gl_display_names:
        draw_name(context, ob, rgb_label, fsize)

    bgl.glLineWidth(1)
    bgl.glDisable(bgl.GL_BLEND)
    bgl.glColor4f(0.0, 0.0, 0.0, 1.0)

class glrun(bpy.types.Operator):
    bl_idname = 'glinfo.glrun' 
    bl_label = 'Display lines'
    bl_description = 'Display lines between objs'

    _handle = None

    @staticmethod
    def handle_add(context):
        if glrun._handle is None:
            glrun._handle = bpy.types.SpaceView3D.draw_handler_add(draw_main, (context,), 'WINDOW', 'POST_PIXEL')
            context.window_manager.run_opengl = True
            
    @staticmethod
    def handle_remove(context):
        if glrun._handle is not None:
            bpy.types.SpaceView3D.draw_handler_remove(glrun._handle, 'WINDOW')
            glrun._handle = None 
            context.window_manager.run_opengl = False

    def execute(self, context):
        if context.area.type == 'VIEW_3D':
            if context.window_manager.run_opengl == False:
                self.handle_add(context)
                context.area.tag_redraw()
            else:
                self.handle_remove(context)
                context.area.tag_redraw()
            return {'FINISHED'}
        else:
            print('3D Viewport is not found')
            return {'CANCELLED'}

class glpanel(bpy.types.Panel):
    bl_idname = 'glinfo.glpanel'
    bl_label = 'Display Object'
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_category = 'Show'

    def draw(self, context):
        lay = self.layout
        scn = context.scene
        box = lay.box()

        if context.window_manager.run_opengl is False:
            icon = 'PLAY'
            txt = 'Display'
        else:
            icon = 'PAUSE'
            txt = 'Hide'
        box.operator('glinfo.glrun', text=txt, icon=icon)
        box.prop(scn, "gl_display_names", toggle=True, icon="OUTLINER_OB_FONT")

    @classmethod
    def register(cls):
        bpy.types.Scene.gl_display_names = bpy.props.BoolProperty(
            name="Names",
            description="Display names for selected meshes.",
            default=True,
        )
        print('register {}'.format(cls.bl_idname))

    @classmethod
    def unregister(cls):
        del bpy.types.Scene.gl_display_names
        print('unregister {}'.format(cls.bl_idname))

# blender add-on部分——tool shelf中的Dynamic display
bl_info2 = {
    "name": "Dynamic display",
    "author": "ksm",
    "location": "View3D > Tools > Dynamic",
    "version": (1, 0, 0),
    "blender": (2, 7, 9),
    "description": "Display memory changes dynamicly"
}

class displayPanel(bpy.types.Panel):
    bl_idname = 'process.DynamicDisplay'
    bl_label = 'Dynamic display'
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_category = 'Dynamic'

    def draw(self, context):
        col = self.layout.column(align=True)
        col.label(text="Control:")
        row = col.row(align=True)
        row.operator("process.prev", text="Prev")
        row.operator("process.next", text="Next")

    @classmethod
    def register(cls):
        print('register {}'.format(cls.bl_idname))

    @classmethod
    def unregister(cls):
        print('unregister {}'.format(cls.bl_idname))

#
#    控制前进，动态显示
#
po = 0 # po指向当前在blender中画出来的network在networks中对应的序号
networks = [] # 存放各个阶段的network

# chenlingling
name_group = {}

class OBJECT_OT_NextButton(bpy.types.Operator):
    bl_idname = "process.next"
    bl_label = "Next Memory"
    
    def execute(self, context):
        global po
        global network
        global networks
        try: # 针对prev后next的情况
            po += 1
            network = networks[po]
            print("reading diff"+ str(po) +".json")
            bpy.ops.object.select_all(action='DESELECT')
            bpy.ops.object.select_all()
            bpy.ops.object.delete()
            draw_network(network)
            return{'FINISHED'}
        except:
            try:
                with open("json/diff"+ str(po) +".json") as in_file:
                    print("reading diff"+ str(po) +".json")
                    new_data = json.load(in_file)
            except IOError:
                print("At the last!")
                po -= 1
                return{'FINISHED'}
            
            # 需要增加节点时
            if new_data["links_add"] != []:
                for link in new_data["links_add"]:
                    if link["target_group"] == 7:
                        link["target"] = link["target"].replace("(", "")
                        link["target"] = link["target"].replace(")", "")
                        link["target"] = link["target"].replace("\'", "")
                        new_target = link["target"].split(", ")[0]
                        link["target"] = new_target
                    link["target_group"] = 8 # 将新增节点的group该为8，用于用红色标识
                # 将links_add中新增的边和edges合并       
                new_edges = network["edges"] + new_data["links_add"]
                # 生成可用的结点，set集合，没有重复
                available_nodes = set(e["source"]
                                    for e in new_edges) | set(e["target"] for e in new_edges)
                labels = list(available_nodes)
                Edges = []
                def generate_edges(*args, **kw):
                    if kw['source'] in args:
                        i = args.index(kw["source"])
                    if kw['target'] in args:
                        j = args.index(kw["target"])
                    tup = (i, j)
                    Edges.append(tup)
                for k in range(len(new_edges)):
                    generate_edges(*labels, **new_edges[k])
                G = ig.Graph(Edges, directed = False)
                layt = G.layout("drl", dim = 3)
                layt.center()
                master_nodes = {}
                for i in range(len(labels)):
                    master_nodes[labels[i]] = {"location":[j*10 for j in layt[i]]}
                
                new_json_str = dumps({"edges": new_edges, "nodes": master_nodes})
                network = json.loads(new_json_str)

                # 添加add_color
                name_group = {}
                for edge in network['edges']:
                    if edge['source'] not in name_group.keys():
                        name_group[edge['source']] = edge['source_group']
                    if edge['target'] not in name_group.keys():
                        name_group[edge['target']] = edge['target_group']
                
                for key in network['nodes'].keys():
                    if name_group[key] == 1:
                        network['nodes'][key]['color'] = 'blue'
                    elif name_group[key] == 2:
                        network['nodes'][key]['color'] = 'yellow'
                    elif name_group[key] == 3:
                        network['nodes'][key]['color'] = 'green'
                    elif name_group[key] == 4:
                        network['nodes'][key]['color'] = 'indigo'
                    elif name_group[key] == 5:
                        network['nodes'][key]['color'] = 'orange'
                    elif name_group[key] == 6:
                        network['nodes'][key]['color'] = 'purple'
                    elif name_group[key] == 7:
                        network['nodes'][key]['color'] = 'gray'
                    elif name_group[key] == 8:
                        network['nodes'][key]['color'] = 'red'
                
            # 需要删除节点时
            if new_data["links_remove"] != []:
                for link in new_data["links_remove"]:
                    if link["target_group"] == 7:
                        link["target"] = link["target"].replace("(", "")
                        link["target"] = link["target"].replace(")", "")
                        link["target"] = link["target"].replace("\'", "")
                        new_target = link["target"].split(", ")[0]
                        link["target"] = new_target
                    # network["edges"].remove(link)
                    for edge in network["edges"]:
                        if edge["source"] == link["source"] and edge["target"] == link["target"]:
                            network["edges"].remove(edge)
                    
                for link in new_data["nodes_remove"]:
                    if link["group"] == 7:
                        link["name"] = link["name"].replace("(", "")
                        link["name"] = link["name"].replace(")", "")
                        link["name"] = link["name"].replace("\'", "")
                        new_name = link["name"].split(", ")[0]
                        link["name"] = new_name
                    del network["nodes"][link["name"]]
                # while len(new_data["nodes_remove"]) != 0:
                #     for i in range(0, len(new_data["nodes_remove"])):
                #         ob_name = new_data["nodes_remove"][i]["name"]
                #         if bpy.data.objects[ob_name].children == ():
                #             bpy.data.objects.get(ob_name).select = True
                #             bpy.ops.object.delete()
                #             new_data["nodes_remove"].remove(new_data["nodes_remove"][i])
                #             del network["nodes"][ob_name]
                #             break
            networks.append(network)
            bpy.ops.object.select_all(action='DESELECT')
            bpy.ops.object.select_all()
            bpy.ops.object.delete()
            draw_network(network)
            
            return{'FINISHED'}

#
#   控制后退
#
class OBJECT_OT_PrevButton(bpy.types.Operator):
    bl_idname = "process.prev"
    bl_label = "Next Memory"
    
    def execute(self, context):
        global po
        global network
        global networks
        if po == 0:
            return{'FINISHED'}
        else:
            po -= 1
            print("reading diff"+ str(po) +".json")
            bpy.ops.object.select_all(action='DESELECT')
            bpy.ops.object.select_all()
            bpy.ops.object.delete()
            network = networks[po]
            draw_network(network)
            return{'FINISHED'}


# 3Dview中UI地区的菜单
class UIPanel(bpy.types.Panel):
    bl_idname = "UIPanel.process"
    bl_label = "Process Panel"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
 
    def draw(self, context):
        # self.layout.operator("getprocess.name", text='Process Name')
        self.layout.label(text = "Process name:")
        #txt = bpy.context.selected_objects[0].name
        #self.layout.label(text = txt)
        ob = context.active_object
        row = self.layout.row()
        row.prop(ob, "name", text="")
    
    @classmethod
    def register(cls):
        print('register {}'.format(cls.bl_idname))

    @classmethod
    def unregister(cls):
        print('unregister {}'.format(cls.bl_idname))
 
def register():
    bpy.utils.register_class(glrun)
    bpy.utils.register_class(glpanel)
    bpy.utils.register_class(displayPanel)
    bpy.utils.register_class(OBJECT_OT_NextButton)
    bpy.utils.register_class(OBJECT_OT_PrevButton)
    bpy.utils.register_class(UIPanel)
    bpy.utils.register_class(HideObject)
    bpy.utils.register_class(ShowObject)
    bpy.utils.register_class(displayPanel_1)
    bpy.utils.register_class(NodeEditOperator)
    bpy.utils.register_class(displayPanel_Jump_3D)
    bpy.utils.register_class(displayPanel_Jump_NodeEdit)
    wm = bpy.types.WindowManager
    wm.run_opengl = bpy.props.BoolProperty(default=False)
    print('{} register complete'.format(bl_info.get('name')))

def unregister():
    bpy.utils.unregister_class(glpanel)
    bpy.utils.unregister_class(glrun)
    bpy.utils.unregister_class(displayPanel)
    bpy.utils.unregister_class(OBJECT_OT_NextButton)
    bpy.utils.unregister_class(OBJECT_OT_PrevButton)        
    bpy.utils.unregister_class(UIPanel)
    bpy.utils.unregister_class(displayPanel_1)
    bpy.utils.unregister_class(DialogOperator)
    bpy.utils.unregister_class(displayPanel_2)
    bpy.utils.unregister_class(HideObject)
    bpy.utils.unregister_class(ShowObject)
    wm = bpy.types.WindowManager
    if 'run_opengl' in wm:
        del wm[p]
    print('{} unregister complete'.format(bl_info.get('name')))

'''
输出json格式内容
'''

def dumps(obj):
    """Outputs json with formatting edits + object handling."""
    return json.dumps(obj, indent=4, sort_keys=True, cls=CustomEncoder)


class CustomEncoder(json.JSONEncoder):

    def encode(self, obj):
        """Fired for every object."""
        s = super(CustomEncoder, self).encode(obj)
        # If uncompressed, postprocess for formatting
        if len(s.splitlines()) > 1:
            s = self.postprocess(s)
        return s

    def postprocess(self, json_string):
        """Displays each entry on its own line."""
        is_compressing, is_hash, compressed, spaces = False, False, [], 0
        for row in json_string.split("\n"):
            if is_compressing:
                if (row[:spaces + 5] == " " * (spaces + 4) +
                        ("\"" if is_hash else "{")):
                    compressed.append(row.rstrip())
                elif (len(row) > spaces and row[:spaces] == " " * spaces and
                        re.match("[\]\}],?", row[spaces:].rstrip())):
                    compressed.append(row.rstrip())
                    is_compressing = False
                else:
                    compressed[-1] += " " + row.strip()
            else:
                compressed.append(row.rstrip())
                if any(a in row for a in ["edges", "nodes"]):
                    # Fix to handle issues that arise with empty lists
                    if "[]" in row:
                        continue
                    spaces = sum(1 for _ in takewhile(str.isspace, row))
                    is_compressing, is_hash = True, "{" in row
        return "\n".join(compressed)


# 颜色RGB指定
colors = { "red": (255, 0, 0), "orange": (255, 108, 0),
           "yellow": (204, 255, 0), "green": (0, 255, 90),
           "blue": (36, 182, 218), "indigo": (0, 18, 255),  
           "purple": (216, 0, 255), "gray": (188, 188, 188)}
          

# 将颜色标准化为[0,1]之间，并且设定materials
for key, value in colors.items():
    value = [x / 255.0 for x in value]
    bpy.data.materials.new(name=key)
    bpy.data.materials[key].diffuse_color = value
    bpy.data.materials[key].specular_intensity = 0.5

# 画出网图的主函数
def draw_network(network):
    """ Takes assembled network/molecule data and draws to blender """
    # 增加原始网格
    bpy.ops.object.select_all(action='DESELECT')
    bpy.ops.mesh.primitive_cone_add(vertices=3, depth=1.414213)
    cube = bpy.context.object

    # 保存所有节点和边的引用
    shapes = []

    # 生成结点
    for key, node in network["nodes"].items():

        # 结点的颜色设定
        col = node.get("color", choice(list(colors.keys())))

        # 复制原始网格并且生成新节点
        node_cube = cube.copy()
        node_cube.data = cube.data.copy()
        #print("*********  node_cube.name : " + key + "     " + network['nodes'][key]['color'])
        node_cube.name = key
        node_cube.location = node["location"]
        node_cube.active_material = bpy.data.materials[col]
        bpy.context.scene.objects.link(node_cube)
        shapes.append(node_cube)
    
    for edge in network["edges"]:
        # 通过遍历获取源和目标的位置
        source_name = edge["source"]
        target_name = edge["target"]
        source_obj = bpy.data.objects[source_name]
        target_obj = bpy.data.objects[target_name]
        # 设置父子关系
        bpy.ops.object.mode_set(mode = 'OBJECT')
        bpy.ops.object.select_all(action='DESELECT')
        # source_obj：父节点
        bpy.context.scene.objects.active = source_obj
        # target_obj：字节点
        target_obj.select = True
        try:
            bpy.ops.object.parent_set()
        except:
            pass
   
    # 删除原始网格
    bpy.ops.object.select_all(action='DESELECT')
    cube.select = True

    # 删除启动时的小方块
    if "Cube" in bpy.data.objects.keys():
        bpy.data.objects.get("Cube").select = True
    bpy.ops.object.delete()

    # 将整个物体居中对齐
    bpy.ops.object.origin_set(type="ORIGIN_GEOMETRY", center="MEDIAN")

    # 刷新场景
    bpy.context.scene.update()


# chenlingling
# 隐藏小的权限节点
class HideObject(bpy.types.Operator):
    """My Object Moving Script"""      # Use this as a tooltip for menu items and buttons.
    bl_idname = "object.hide"        # Unique identifier for buttons and menu items to reference.
    bl_label = "Hide the object "         # Display name in the interface.
    bl_options = {'REGISTER', 'UNDO'}  # Enable undo for the operator.

    def execute(self, context):        # execute() is called when running the operator.

    # The original script
        scene = context.scene
        print("Execute")
        for obj in bpy.data.objects:
            obj_name = obj.name
            #print("Obj name is : " + obj_name)
            if obj_name in network['nodes']:
                #print("@@@@@  Color is : " + network['nodes'][obj_name]['color'])
                obj_color = network['nodes'][obj_name]['color']
                # color为gray,即group为7,隐藏这些点
                if obj_color == 'gray':
                    obj.hide = True
            

        return {'FINISHED'}            # Lets Blender know the operator finished successfully.

    def register():
            print("Registered class: HideObject ")

    def unregister():
            print("Unregistered class: HideObject ")

# chenlingling
# 显示小的权限节点
class ShowObject(bpy.types.Operator):
    """My Object Moving Script"""      # Use this as a tooltip for menu items and buttons.
    bl_idname = "object.show"        # Unique identifier for buttons and menu items to reference.
    bl_label = "Show the object "         # Display name in the interface.
    bl_options = {'REGISTER', 'UNDO'}  # Enable undo for the operator.

    def execute(self, context):        # execute() is called when running the operator.

    # The original script
        scene = context.scene
        print("Execute")
        for obj in bpy.data.objects:
            obj_name = obj.name
            #print("Obj name is : " + obj_name)
            if obj_name in network['nodes']:
                #print("@@@@@  Color is : " + network['nodes'][obj_name]['color'])
                obj_color = network['nodes'][obj_name]['color']
                # color为gray,即group为7,显示这些点
                if obj_color == 'gray':
                    obj.hide = False
            

        return {'FINISHED'}            # Lets Blender know the operator finished successfully.

    def register():
            print("Registered class: HideObject ")

    def unregister():
            print("Unregistered class: HideObject ")

# chenlingling
# 隐藏/显示小权限节点的Panel
class displayPanel_1(bpy.types.Panel):
    bl_idname = 'process.Hide_Show_Object'
    bl_label = 'Hide/Show Object'
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_category = 'Hide_Show_Object'


    def draw(self, context):
        self.layout.operator("object.hide", text="Hide")
        self.layout.operator("object.show", text="Show")

    @classmethod
    def register(cls):
        print('register {}'.format(cls.bl_idname))

    @classmethod
    def unregister(cls):
        print('unregister {}'.format(cls.bl_idname))


# chenlingling
# 点击节点后弹窗，弹窗中显示节点ID
class NodeEditOperator(bpy.types.Operator):
    bl_idname = "object.nodeedit_operator"
    bl_label = "The node's process tree"

    testprop = bpy.props.StringProperty(name = "Node")

    def execute(self, context):
        print(self.testprop)
        return {'FINISHED'}

    def invoke(self, context, event):
        wm = context.window_manager
        # 弹窗里的内容即为选中的节点的name
        if len(context.selected_objects) == 0:
            self.testprop = "No node is selected"
        else:
            self.testprop = context.selected_objects[0].name
        return wm.invoke_props_dialog(self)

# chenlingling
# 从3D_View跳转到Node_Edit
class displayPanel_Jump_3D(bpy.types.Panel):
    bl_idname = 'process.Choose_The_Node'
    bl_label = 'Jump'
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_category = 'Jump'

 
    def draw(self, context):
        self.layout.operator('object.nodeedit_operator', text="process tree")
        op = self.layout.operator('wm.context_set_enum', text="Node Edit")
        op.data_path, op.value = 'area.type', 'NODE_EDITOR'


    @classmethod
    def register(cls):
        print('register {}'.format(cls.bl_idname))

    @classmethod
    def unregister(cls):
        print('unregister {}'.format(cls.bl_idname))


# chenlingling
# 从Node_Edit跳转到3D_View
class displayPanel_Jump_NodeEdit(bpy.types.Panel):
    bl_idname = 'process.Choose_The_Node'
    bl_label = 'Jump'
    bl_space_type = 'NODE_EDITOR'
    bl_region_type = 'TOOLS'
    bl_category = 'Jump'

 
    def draw(self, context):
        op_1 = self.layout.operator('wm.context_set_enum', text="3D View")
        op_1.data_path, op_1.value = 'area.type', 'VIEW_3D'

    @classmethod
    def register(cls):
        print('register {}'.format(cls.bl_idname))

    @classmethod
    def unregister(cls):
        print('unregister {}'.format(cls.bl_idname))




if __name__ == "__main__":
    try:
        with open(r"json/res0.json") as in_file:
            edges = json.load(in_file)
    except IOError:
        with open(sys.argv[-1]) as in_file:
            edges = json.load(in_file)
    for link in edges["links"]:
        if link["target_group"] == 7:
            link["target"] = link["target"].replace("(", "")
            link["target"] = link["target"].replace(")", "")
            link["target"] = link["target"].replace("\'", "")
            new_target = link["target"].split(", ")[0]
            link["target"] = new_target

    edges = edges["links"]

    #获取结点集合
    available_nodes = set(e["source"] for e in edges) | set(e["target"] for e in edges)

    labels = list(available_nodes)
    Edges = []

    def generate_edges(*args, **kw):
        if kw['source'] in args:
            i = args.index(kw["source"])
        if kw['target'] in args:
            j = args.index(kw["target"])
        tup = (i, j)
        Edges.append(tup)
    

    for k in range(len(edges)):
        generate_edges(*labels, **edges[k])

    #********************************
    G = ig.Graph(Edges, directed = False)
    layt = G.layout("drl", dim = 3)
    layt.center()
    master_nodes = {}
    for i in range(len(labels)):
        master_nodes[labels[i]] = {"location":[j*10 for j in layt[i]]}

    json_str = dumps({"edges": edges, "nodes": master_nodes})
    network = json.loads(json_str)

    # 添加add_color
    #name_group = {}
    name_group.clear()
    for edge in network['edges']:
        if edge['source'] not in name_group.keys():
            name_group[edge['source']] = edge['source_group']
        if edge['target'] not in name_group.keys():
            name_group[edge['target']] = edge['target_group']
    
    for key in network['nodes'].keys():  
        if name_group[key] == 1:
            network['nodes'][key]['color'] = 'blue'
        elif name_group[key] == 2:
            network['nodes'][key]['color'] = 'yellow'
        elif name_group[key] == 3:
            network['nodes'][key]['color'] = 'green'
        elif name_group[key] == 4:
            network['nodes'][key]['color'] = 'indigo'
        elif name_group[key] == 5:
            network['nodes'][key]['color'] = 'orange'
        elif name_group[key] == 6:
            network['nodes'][key]['color'] = 'purple'
        elif name_group[key] == 7:
            network['nodes'][key]['color'] = 'gray'
    network_copy = deepcopy(network)
    networks.append(network_copy)
    #print(network)
    draw_network(network)

    
    try:
        unregister()
    except Exception as e:
        print(e)
        pass
    finally:
        register()